/******************************************************************************
 *                  NJS's MSP430 LaunchPad Oscilloscope
 * 
 * Description:	This code turns the launchpad into a simple (slow)
 *				oscilloscope using a bi-directional software UART.
 * 				The MCU will accept ascii commands from the computer
 * 				for single measurment of a channel (internal and 
 * 				external) and also continous measuring of external
 * 				channels.
 *
 * 				This code was originally created for "NJC's MSP430
 * 				LaunchPad Blog".
 * 
 * Author:	Nicholas J. Conn - http://msp430launchpad.com
 * Email:	webmaster at msp430launchpad.com
 * Date:	08-29-10
 ******************************************************************************/

#include	"msp430g2231.h"
#include	"stdbool.h"

// protocol arguments are in the range 0x40 (-1) to 0x60 (+31) inclusive
#define 	ARG_MIN     0x40
#define 	ARG_MAX     0x60
#define 	ARG_ZERO    0x41
#define 	ARG_ACK     0x20    // to read more status arguments
#define 	CMD_LANGUAGE    'l' // set si language <1>
#define 	CMD_TIMEOUT     'o' // set timeout <1>
#define 	STS_SUCCESS     'o' // no errors status

#define		Bit_time		104		// 9600 Baud, SMCLK=1MHz (1MHz/9600)=104
#define		Bit_time_5		52		// Time for half a bit.

// ASCII values for the commands
#define		TXD				BIT1    // TXD on P1.1
#define		RXD				BIT2	// RXD on P1.2
#define		RUN				1
#define		RIGHT			0x32
#define		LEFT			0x33
#define		STOP			0x34

unsigned char BitCnt,lt;		// Bit count, used when transmitting byte
unsigned char TXByte;		// Value sent over UART when Transmit() is called
unsigned char RXByte;		// Value recieved once hasRecieved is set

unsigned int i;				// for loop variable

bool isReceiving;			// Status for when the device is receiving
bool hasReceived;			// Lets the program know when a byte is received
void delay_ms(unsigned int ms )
{
      unsigned int i;
      for (i = 0; i<= ms; i++)
        __delay_cycles(500); //Built-in function that suspends the execution for 500 cicles
}

void delay_us(unsigned int us )
{
      unsigned int i;
      for (i = 0; i<= us/2; i++) 
        __delay_cycles(1);
}
// Function Definitions
void Receive(void);

/**
 * Transmits the value currently in TXByte. The function waits till it is
 *   finished transmiting before it returns.
 **/ 

void Transmit()
{ 
	while(isReceiving);					// Wait for RX completion
	
  	TXByte |= 0x100;					// Add stop bit to TXByte (which is logical 1)
  	TXByte = TXByte << 1;				// Add start bit (which is logical 0)
  	BitCnt = 0xA;						// Load Bit counter, 8 bits + ST/SP
  	
  	CCTL0 = OUT;						// TXD Idle as Mark
  	TACTL = TASSEL_2 + MC_2;			// SMCLK, continuous mode
  	CCR0 = TAR;							// Initialize compare register  
  	CCR0 += Bit_time;					// Set time till first bit  
  	CCTL0 =  CCIS0 + OUTMOD0 + CCIE;	// Set signal, intial value, enable interrupts
  	while ( CCTL0 & CCIE );				// Wait for previous TX completion
}
//******************************************************************************
//**** Set up VRbot by ask ID, English language, 5 second timeout *************
//******************************************************************************
unsigned char v_setup(){
	/*	
TXByte = 'x'; Transmit();
if(RXByte == 'w') { delay_ms(500); TXByte = 'x'; Transmit();}
delay_ms(500);
if(RXByte != 'x') return 1;
__delay_cycles(5000);	*/			
			
P1OUT |= BIT0;
		delay_ms(5000);		
P1OUT &= ~BIT0;	
		delay_ms(5000);	

TXByte = 'l'; Transmit(); 
TXByte = 'A'; Transmit();
delay_ms(500);
if(RXByte == 'w') return 1;

P1OUT |= BIT0;
		delay_ms(5000);		
P1OUT &= ~BIT0;	
		delay_ms(5000);	
		
TXByte = CMD_TIMEOUT; Transmit();
TXByte = (ARG_ZERO+5); Transmit();
delay_ms(500);
if(RXByte != STS_SUCCESS) return 1;


P1OUT |= BIT0;
		delay_ms(5000);		
P1OUT &= ~BIT0;	
		delay_ms(5000);	
		
return 0;
}


//******************************************************************************
//**** VRbot recognize SI or SD command. require command and group ************
//**** return index if success or other status if fail ************
//*****************************************************************************
unsigned char v_recognize() {
unsigned char rslt;
P1OUT |= BIT6;
delay_ms(3000);
P1OUT &= ~BIT6;
TXByte = 'd'; Transmit();
TXByte = 'C'; Transmit();
delay_ms(3000);
rslt = RXByte;
if(rslt == 'r'){
	
	P1OUT |= BIT0; delay_ms(2000); P1OUT &= ~BIT0;

	delay_ms(100);
	TXByte = ARG_ACK; Transmit();
	return (RXByte-ARG_ZERO);
	}
	delay_ms(5000);
return 99;
}


void main(void)
{
	WDTCTL = WDTPW + WDTHOLD;		// Stop WDT
  
	BCSCTL1 = CALBC1_1MHZ;			// Set range
	DCOCTL = CALDCO_1MHZ;			// SMCLK = DCO = 1MHz  

	P1SEL |= TXD;					// Connected TXD to timer
	P1DIR |= TXD;

	P1IES |= RXD;					// RXD Hi/lo edge interrupt
	P1IFG &= ~RXD;					// Clear RXD (flag) before enabling interrupt
	P1IE |= RXD;					// Enable RXD interrupt
	
	P1DIR |= BIT0;					
	P1OUT &= ~BIT0;					// Turn off LED at P1.0
				//	P1OUT |= BIT0;
	
	P1DIR |= BIT4;					
	P1OUT &= ~BIT4;					// Turn off LED at P1.4
	
	P1DIR |= BIT6;					
	P1OUT &= ~BIT6;					// Turn off LED at P1.4
				//	P1OUT |= BIT6;
  
		delay_ms(5000);
		
	isReceiving = false;			// Set initial values
	hasReceived = false;
	
	__bis_SR_register(GIE);			// interrupts enabled\
	
	
	TXByte = 'd'; Transmit(); 
	TXByte = 'C'; Transmit();
	delay_ms(500);
	if(RXByte == 'w')P1OUT |= BIT6;
	/*if(v_setup()==0)
	{
	while(1)
	{
		lt=v_recognize();
		if(lt!=99)
		{
			P1OUT |= BIT6;	
//			Receive();
		
	//	if (~hasReceived)			// Loop again if either flag is set
    	//	__bis_SR_register(CPUOFF + GIE);	// LPM0, the ADC interrupt will wake the processor up.
		}		
		else
		{
			P1OUT &= ~BIT6;
			delay_ms(5000);
		}
	}
	}
	else
	{
	//	P1OUT |= BIT0;		
	//		P1OUT &= ~BIT6;
	//	delay_ms(5000);
		
		P1OUT |= BIT6;		
			P1OUT &= ~BIT0;
		delay_ms(5000);
	}*/
}

/**
 * Handles the received byte and calls the needed functions.\
 **/
void Receive()
{
	hasReceived = false;	// Clear the flag
	switch(lt)			// Switch depending on command value received
	{
		case RUN:
			P1OUT |= BIT0;				
			//P1OUT |= BIT4;	
					
		//	P1OUT &= ~BIT5;				
			P1OUT &= ~BIT6;	
			break;

		case STOP:		
			P1OUT &= ~BIT0;
			P1OUT &= ~BIT4;
		//	P1OUT |= BIT5;				
			P1OUT |= BIT6;	
			break;
        	
		case RIGHT:		
			P1OUT &= ~BIT0;					
			P1OUT |= BIT4;
			break;
        	
		case LEFT:		
			P1OUT &= ~BIT4;					
			P1OUT |= BIT0;
			break;
            
		default:;
    }
}

/**
 * Starts the receive timer, and disables any current transmission.
 **/
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{  	
	isReceiving = true;
	
	P1IE &= ~RXD;				// Disable RXD interrupt
	P1IFG &= ~RXD;				// Clear RXD IFG (interrupt flag)
	
  	TACTL = TASSEL_2 + MC_2;	// SMCLK, continuous mode
  	CCR0 = TAR;					// Initialize compare register
  	CCR0 += Bit_time_5;			// Set time till first bit
	CCTL0 = OUTMOD1 + CCIE;		// Dissable TX and enable interrupts
	
	RXByte = 0;					// Initialize RXByte
	BitCnt = 0x9;				// Load Bit counter, 8 bits + ST
}


/**
 * Timer interrupt routine. This handles transmiting and receiving bytes.
 **/
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
	if(!isReceiving)
	{
		CCR0 += Bit_time;				// Add Offset to CCR0  
		if ( BitCnt == 0)				// If all bits TXed
		{
  			TACTL = TASSEL_2;			// SMCLK, timer off (for power consumption)
			CCTL0 &= ~ CCIE ;			// Disable interrupt
		}
		else
		{
			CCTL0 |=  OUTMOD2;			// Set TX bit to 0
			if (TXByte & 0x01)
				CCTL0 &= ~ OUTMOD2;		// If it should be 1, set it to 1
			TXByte = TXByte >> 1;
			BitCnt --;
		}
	}
	else
	{
		CCR0 += Bit_time;						// Add Offset to CCR0  
		if ( BitCnt == 0)
		{
  			TACTL = TASSEL_2;					// SMCLK, timer off (for power consumption)
			CCTL0 &= ~ CCIE ;					// Disable interrupt
			
			isReceiving = false;
			
			P1IFG &= ~RXD;						// clear RXD IFG (interrupt flag)
			P1IE |= RXD;						// enabled RXD interrupt
			
			if ( (RXByte & 0x201) == 0x200)		// Validate the start and stop bits are correct
			{
				RXByte = RXByte >> 1;			// Remove start bit
				RXByte &= 0xFF;					// Remove stop bit
				hasReceived = true;
			}
  			__bic_SR_register_on_exit(CPUOFF);	// Enable CPU so the main while loop continues
		}
		else
		{
			if ( (P1IN & RXD) == RXD)			// If bit is set?
				RXByte |= 0x400;				// Set the value in the RXByte 
			RXByte = RXByte >> 1;				// Shift the bits down
			BitCnt --;
		}
	}
}
